home *** CD-ROM | disk | FTP | other *** search
/ Mac Format 1995 June / MacFormat 25.iso / Shareware City / Developers / OutOfPhase1.1 Source / OutOfPhase Folder / FrameObject.c < prev    next >
Text File  |  1994-08-15  |  14KB  |  465 lines

  1. /* FrameObject.c */
  2. /*****************************************************************************/
  3. /*                                                                           */
  4. /*    Out Of Phase:  Digital Music Synthesis on General Purpose Computers    */
  5. /*    Copyright (C) 1994  Thomas R. Lawrence                                 */
  6. /*                                                                           */
  7. /*    This program is free software; you can redistribute it and/or modify   */
  8. /*    it under the terms of the GNU General Public License as published by   */
  9. /*    the Free Software Foundation; either version 2 of the License, or      */
  10. /*    (at your option) any later version.                                    */
  11. /*                                                                           */
  12. /*    This program is distributed in the hope that it will be useful,        */
  13. /*    but WITHOUT ANY WARRANTY; without even the implied warranty of         */
  14. /*    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the          */
  15. /*    GNU General Public License for more details.                           */
  16. /*                                                                           */
  17. /*    You should have received a copy of the GNU General Public License      */
  18. /*    along with this program; if not, write to the Free Software            */
  19. /*    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.              */
  20. /*                                                                           */
  21. /*    Thomas R. Lawrence can be reached at tomlaw@world.std.com.             */
  22. /*                                                                           */
  23. /*****************************************************************************/
  24.  
  25. #include "MiscInfo.h"
  26. #include "Audit.h"
  27. #include "Debug.h"
  28. #include "Definitions.h"
  29.  
  30. #include "FrameObject.h"
  31. #include "NoteObject.h"
  32. #include "Memory.h"
  33. #include "DataMunging.h"
  34. #include "NoteImages.h"
  35. #include "Frequency.h"
  36. #include "StaffCalibration.h"
  37. #include "Fractions.h"
  38.  
  39.  
  40. struct FrameObjectRec
  41.     {
  42.         NoteObjectRec**        NoteArray; /* too much overhead to use ArrayRec object */
  43.         OrdType                        Width; /* cached width value; 0 == unknown */
  44.     };
  45.  
  46.  
  47. /* allocate a new frame. */
  48. FrameObjectRec*                NewFrame(void)
  49.     {
  50.         FrameObjectRec*            Frame;
  51.  
  52.         Frame = (FrameObjectRec*)AllocPtrCanFail(sizeof(FrameObjectRec),"FrameObjectRec");
  53.         if (Frame == NIL)
  54.             {
  55.              FailurePoint1:
  56.                 return NIL;
  57.             }
  58.         Frame->NoteArray = (NoteObjectRec**)AllocPtrCanFail(0,"FrameNoteObjectArray");
  59.         if (Frame->NoteArray == NIL)
  60.             {
  61.              FailurePoint2:
  62.                 ReleasePtr((char*)Frame);
  63.                 goto FailurePoint1;
  64.             }
  65.         Frame->Width = 0;
  66.         return Frame;
  67.     }
  68.  
  69.  
  70. /* dispose of a frame and all notes it contains.  be careful here since this won't */
  71. /* worry about tie references to notes contained in the frame. */
  72. void                                    DisposeFrameAndContents(FrameObjectRec* Frame)
  73.     {
  74.         long                                Scan;
  75.  
  76.         Scan = NumNotesInFrame(Frame) - 1;
  77.         while (Scan >= 0)
  78.             {
  79.                 DisposeNote(Frame->NoteArray[Scan]);
  80.                 Scan -= 1;
  81.             }
  82.         ReleasePtr((char*)(Frame->NoteArray));
  83.         ReleasePtr((char*)Frame);
  84.     }
  85.  
  86.  
  87. /* get the number of notes contained in the frame */
  88. long                                    NumNotesInFrame(FrameObjectRec* Frame)
  89.     {
  90.         CheckPtrExistence(Frame);
  91.         return PtrSize((char*)(Frame->NoteArray)) / sizeof(NoteObjectRec*);
  92.     }
  93.  
  94.  
  95. /* get the note specified by the index from the frame object */
  96. struct NoteObjectRec*    GetNoteFromFrame(FrameObjectRec* Frame, long Index)
  97.     {
  98.         CheckPtrExistence(Frame);
  99.         PRNGCHK(Frame->NoteArray,&(Frame->NoteArray[Index]),sizeof(NoteObjectRec*));
  100.         return Frame->NoteArray[Index];
  101.     }
  102.  
  103.  
  104. /* delete a note in the frame.  returns True if successful. */
  105. MyBoolean                            DeleteNoteFromFrame(FrameObjectRec* Frame, long Index)
  106.     {
  107.         NoteObjectRec**            NewArray;
  108.  
  109.         CheckPtrExistence(Frame);
  110.         NewArray = (NoteObjectRec**)RemoveEntryFromArrayCopy((char*)(Frame->NoteArray),
  111.             Index,sizeof(NoteObjectRec*));
  112.         if (NewArray != NIL)
  113.             {
  114.                 ReleasePtr((char*)(Frame->NoteArray));
  115.                 Frame->NoteArray = NewArray;
  116.                 Frame->Width = 0;
  117.                 return True;
  118.             }
  119.          else
  120.             {
  121.                 return False;
  122.             }
  123.     }
  124.  
  125.  
  126. /* append a note to the frame.  returns True if successful. */
  127. MyBoolean                            AppendNoteToFrame(FrameObjectRec* Frame, struct NoteObjectRec* Note)
  128.     {
  129.         NoteObjectRec**            NewRef;
  130.         long                                OldSize;
  131.  
  132.         CheckPtrExistence(Frame);
  133.         CheckPtrExistence(Note);
  134.         OldSize = PtrSize((char*)(Frame->NoteArray));
  135.         ERROR(IsThisACommandFrame(Frame),PRERR(ForceAbort,
  136.             "AppendNoteToFrame:  adding note to command frame"));
  137.         ERROR(!IsThisACommandFrame(Frame) && (NumNotesInFrame(Frame) > 0)
  138.             && IsItACommand(Note),PRERR(ForceAbort,
  139.             "AppendNoteToFrame:  adding command to note frame"));
  140.         NewRef = (NoteObjectRec**)ResizePtr((char*)(Frame->NoteArray),
  141.             OldSize + sizeof(NoteObjectRec*));
  142.         if (NewRef == NIL)
  143.             {
  144.                 return False;
  145.             }
  146.         Frame->NoteArray = NewRef;
  147.         Frame->NoteArray[OldSize / sizeof(NoteObjectRec*)] = Note;
  148.         Frame->Width = 0;
  149.         return True;
  150.     }
  151.  
  152.  
  153. /* find out if this is a command frame.  command frames are allowed to have a */
  154. /* single command and nothing else in them */
  155. MyBoolean                            IsThisACommandFrame(FrameObjectRec* Frame)
  156.     {
  157.         CheckPtrExistence(Frame);
  158.         return (NumNotesInFrame(Frame) == 1) && IsItACommand(Frame->NoteArray[0]);
  159.     }
  160.  
  161.  
  162. /* find out the width of this command/note frame and draw it if the flag is set. */
  163. /* it assumes the clipping rectangle is set up properly.  the X and Y parameters */
  164. /* specify the left edge of the note and the Middle C line. */
  165. /* this routine does not handle drawing of ties. */
  166. OrdType                                WidthOfFrameAndDraw(WinType* Window, OrdType X, OrdType Y,
  167.                                                 FontType Font, FontSizeType FontSize, OrdType FontHeight,
  168.                                                 FrameObjectRec* Frame, MyBoolean ActuallyDraw,
  169.                                                 MyBoolean GreyedOut)
  170.     {
  171.         OrdType                            Width;
  172.  
  173.         /* this caching of the width of the frame should speed things up */
  174.         if ((Frame->Width != 0) && !ActuallyDraw)
  175.             {
  176.                 /* we can only do this if we aren't drawing! */
  177.                 return Frame->Width;
  178.             }
  179.         /* we should be able to find ways of overlapping the notes if they won't */
  180.         /* be on top of each other on screen but we're not going to for now. */
  181.         if (IsThisACommandFrame(Frame))
  182.             {
  183.                 /* it's a command frame, so draw using the special command drawing routines */
  184.                 Width = DrawCommandOnScreen(Window,X,Y,Font,FontSize,FontHeight,
  185.                     GetNoteFromFrame(Frame,0),ActuallyDraw,GreyedOut);
  186.             }
  187.          else
  188.             {
  189.                 long                                Limit;
  190.                 long                                Scan;
  191.  
  192.                 /* we have to draw the notes ourselves. */
  193.                 X -= LEFTNOTEEDGEINSET;
  194.                 Width = 0;
  195.                 Limit = NumNotesInFrame(Frame);
  196.                 for (Scan = 0; Scan < Limit; Scan += 1)
  197.                     {
  198.                         NoteObjectRec*            Note;
  199.  
  200.                         /* get the note to be drawn */
  201.                         Note = GetNoteFromFrame(Frame,Scan);
  202.                         CheckPtrExistence(Note);
  203.                         /* do the icon stuff */
  204.                         if (ActuallyDraw)
  205.                             {
  206.                                 Bitmap*                            Image;
  207.                                 Bitmap*                            Mask;
  208.                                 OrdType                            NoteOffset;
  209.  
  210.                                 /* first, obtain the proper image for the duration */
  211.                                 if (!GetNoteIsItARest(Note))
  212.                                     {
  213.                                         switch (GetNoteDuration(Note))
  214.                                             {
  215.                                                 default:
  216.                                                     EXECUTE(PRERR(ForceAbort,
  217.                                                         "LengthOfCommandFrameAndDraw:  bad duration value"));
  218.                                                     break;
  219.                                                 case e64thNote:
  220.                                                     Image = SixtyFourthNoteImage;
  221.                                                     Mask = SixtyFourthNoteMask;
  222.                                                     break;
  223.                                                 case e32ndNote:
  224.                                                     Image = ThirtySecondNoteImage;
  225.                                                     Mask = ThirtySecondNoteMask;
  226.                                                     break;
  227.                                                 case e16thNote:
  228.                                                     Image = SixteenthNoteImage;
  229.                                                     Mask = SixteenthNoteMask;
  230.                                                     break;
  231.                                                 case e8thNote:
  232.                                                     Image = EighthNoteImage;
  233.                                                     Mask = EighthNoteMask;
  234.                                                     break;
  235.                                                 case e4thNote:
  236.                                                     Image = QuarterNoteImage;
  237.                                                     Mask = QuarterNoteMask;
  238.                                                     break;
  239.                                                 case e2ndNote:
  240.                                                     Image = HalfNoteImage;
  241.                                                     Mask = HalfNoteMask;
  242.                                                     break;
  243.                                                 case eWholeNote:
  244.                                                     Image = WholeNoteImage;
  245.                                                     Mask = WholeNoteMask;
  246.                                                     break;
  247.                                                 case eDoubleNote:
  248.                                                     Image = DoubleNoteImage;
  249.                                                     Mask = DoubleNoteMask;
  250.                                                     break;
  251.                                                 case eQuadNote:
  252.                                                     Image = QuadNoteImage;
  253.                                                     Mask = QuadNoteMask;
  254.                                                     break;
  255.                                             }
  256.                                     }
  257.                                  else
  258.                                     {
  259.                                         switch (GetNoteDuration(Note))
  260.                                             {
  261.                                                 default:
  262.                                                     EXECUTE(PRERR(ForceAbort,
  263.                                                         "LengthOfCommandFrameAndDraw:  bad duration value"));
  264.                                                     break;
  265.                                                 case e64thNote:
  266.                                                     Image = SixtyFourthRestImage;
  267.                                                     Mask = SixtyFourthRestMask;
  268.                                                     break;
  269.                                                 case e32ndNote:
  270.                                                     Image = ThirtySecondRestImage;
  271.                                                     Mask = ThirtySecondRestMask;
  272.                                                     break;
  273.                                                 case e16thNote:
  274.                                                     Image = SixteenthRestImage;
  275.                                                     Mask = SixteenthRestMask;
  276.                                                     break;
  277.                                                 case e8thNote:
  278.                                                     Image = EighthRestImage;
  279.                                                     Mask = EighthRestMask;
  280.                                                     break;
  281.                                                 case e4thNote:
  282.                                                     Image = QuarterRestImage;
  283.                                                     Mask = QuarterRestMask;
  284.                                                     break;
  285.                                                 case e2ndNote:
  286.                                                     Image = HalfRestImage;
  287.                                                     Mask = HalfRestMask;
  288.                                                     break;
  289.                                                 case eWholeNote:
  290.                                                     Image = WholeRestImage;
  291.                                                     Mask = WholeRestMask;
  292.                                                     break;
  293.                                                 case eDoubleNote:
  294.                                                     Image = DoubleRestImage;
  295.                                                     Mask = DoubleRestMask;
  296.                                                     break;
  297.                                                 case eQuadNote:
  298.                                                     Image = QuadRestImage;
  299.                                                     Mask = QuadRestMask;
  300.                                                     break;
  301.                                             }
  302.                                     }
  303.                                 /* duplicate images so we can modify them */
  304.                                 Image = DuplicateBitmap(Image);
  305.                                 if (Image == NIL)
  306.                                     {
  307.                                         goto FailurePoint;
  308.                                     }
  309.                                 Mask = DuplicateBitmap(Mask);
  310.                                 if (Mask == NIL)
  311.                                     {
  312.                                         DisposeBitmap(Image);
  313.                                         goto FailurePoint;
  314.                                     }
  315.                                 /* now, handle divisions */
  316.                                 switch (GetNoteDurationDivision(Note))
  317.                                     {
  318.                                         default:
  319.                                             EXECUTE(PRERR(ForceAbort,
  320.                                                 "LengthOfCommandFrameAndDraw:  bad division value"));
  321.                                             break;
  322.                                         case eDiv1Modifier:
  323.                                             /* no change */
  324.                                             break;
  325.                                         case eDiv3Modifier:
  326.                                             BitmapOrIntoBitmap(Div3Image,Image);
  327.                                             BitmapOrIntoBitmap(Div3Mask,Mask);
  328.                                             break;
  329.                                         case eDiv5Modifier:
  330.                                             BitmapOrIntoBitmap(Div5Image,Image);
  331.                                             BitmapOrIntoBitmap(Div5Mask,Mask);
  332.                                             break;
  333.                                         case eDiv7Modifier:
  334.                                             BitmapOrIntoBitmap(Div7Image,Image);
  335.                                             BitmapOrIntoBitmap(Div7Mask,Mask);
  336.                                             break;
  337.                                     }
  338.                                 /* handle dots */
  339.                                 if (GetNoteDotStatus(Note))
  340.                                     {
  341.                                         BitmapOrIntoBitmap(DotImage,Image);
  342.                                         BitmapOrIntoBitmap(DotMask,Mask);
  343.                                     }
  344.                                 /* sharps and flats require more clever handling */
  345.                                 if ((GetNoteFlatOrSharpStatus(Note) & eSharpModifier) != 0)
  346.                                     {
  347.                                         BitmapOrIntoBitmap(SharpImage,Image);
  348.                                         BitmapOrIntoBitmap(SharpMask,Mask);
  349.                                     }
  350.                                 if ((GetNoteFlatOrSharpStatus(Note) & eFlatModifier) != 0)
  351.                                     {
  352.                                         BitmapOrIntoBitmap(FlatImage,Image);
  353.                                         BitmapOrIntoBitmap(FlatMask,Mask);
  354.                                     }
  355.                                 /* check greying status */
  356.                                 if (GreyedOut)
  357.                                     {
  358.                                         BitmapAndIntoBitmap(GreyMask,Image);
  359.                                     }
  360.                                 /* perform the drawing */
  361.                                 NoteOffset = Y + ConvertPitchToPixel(GetNotePitch(Note),
  362.                                     GetNoteFlatOrSharpStatus(Note))
  363.                                     - TOPNOTESTAFFINTERSECT - GetCenterNotePixel();
  364.                                 BicBitmap(Window,X,NoteOffset,Mask);
  365.                                 OrBitmap(Window,X,NoteOffset,Image);
  366.                                 /* dump the bitmaps */
  367.                                 DisposeBitmap(Mask);
  368.                                 DisposeBitmap(Image);
  369.                                 /* increment X for the next time around */
  370.                                 X += INTERNALSEPARATION;
  371.                             }
  372.  
  373.                         /* update the width count */
  374.                      FailurePoint:
  375.                         if (Width == 0)
  376.                             {
  377.                                 /* first time you get the whole width */
  378.                                 Width = ICONWIDTH - LEFTNOTEEDGEINSET;
  379.                             }
  380.                          else
  381.                             {
  382.                                 /* other times, you just get whatever extra there is */
  383.                                 Width += INTERNALSEPARATION;
  384.                             }
  385.                     }
  386.             }
  387.         Frame->Width = Width;
  388.         return Width;
  389.     }
  390.  
  391.  
  392. /* find out the duration of the specified frame.  returns the duration of the */
  393. /* frame as a fraction */
  394. void                                    DurationOfFrame(FrameObjectRec* Frame, struct FractionRec* Frac)
  395.     {
  396.         long                                Scan;
  397.         long                                Limit;
  398.         NoteObjectRec*            Note;
  399.  
  400.         CheckPtrExistence(Frame);
  401.         if (IsThisACommandFrame(Frame))
  402.             {
  403.                 Frac->Integer = 0;
  404.                 Frac->Fraction = 0;
  405.                 Frac->Denominator = (64*3*5*7*2);
  406.                 return;
  407.             }
  408.         Limit = NumNotesInFrame(Frame);
  409.         ERROR(Limit < 1,PRERR(ForceAbort,"DurationOfFrame called on empty frame"));
  410.         /* obtain duration of first element */
  411.         Note = GetNoteFromFrame(Frame,0);
  412.         GetNoteDurationFrac(Note,Frac);
  413.         for (Scan = 0; Scan < Limit; Scan += 1)
  414.             {
  415.                 FractionRec                    TempFrac;
  416.  
  417.                 Note = GetNoteFromFrame(Frame,Scan);
  418.                 GetNoteDurationFrac(Note,&TempFrac);
  419.                 if (FracGreaterThan(Frac,&TempFrac))
  420.                     {
  421.                         /* choose smallest one */
  422.                         *Frac = TempFrac;
  423.                     }
  424.             }
  425.     }
  426.  
  427.  
  428. /* make a total (deep) copy of the frame and the notes it contains */
  429. FrameObjectRec*                DeepDuplicateFrame(FrameObjectRec* Frame)
  430.     {
  431.         FrameObjectRec*            Copy;
  432.         long                                Limit;
  433.         long                                Scan;
  434.  
  435.         CheckPtrExistence(Frame);
  436.         Copy = NewFrame();
  437.         if (Copy == NIL)
  438.             {
  439.              FailurePoint1:
  440.                 return NIL;
  441.             }
  442.  
  443.         Limit = NumNotesInFrame(Frame);
  444.         for (Scan = 0; Scan < Limit; Scan += 1)
  445.             {
  446.                 NoteObjectRec*            NoteCopy;
  447.  
  448.                 NoteCopy = DeepCopyNoteObject(GetNoteFromFrame(Frame,Scan));
  449.                 if (NoteCopy == NIL)
  450.                     {
  451.                      FailurePoint2:
  452.                         DisposeFrameAndContents(Copy);
  453.                         goto FailurePoint1;
  454.                     }
  455.                 if (!AppendNoteToFrame(Copy,NoteCopy))
  456.                     {
  457.                      FailurePoint2a:
  458.                         DisposeNote(NoteCopy);
  459.                         goto FailurePoint2;
  460.                     }
  461.             }
  462.  
  463.         return Copy;
  464.     }
  465.